﻿using FastReport;
using FastReport.Data.JsonConnection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TemplatesPrint.DBHelper;
using TemplatesPrint.DTO;
using TemplatesPrint.EntityHandle;
using TemplatesPrint.Entitys;
using TemplatesPrint.MySqlEntitys;

namespace TemplatesPrint.Tools
{
    public class PrintTheadTool
    {
        public static void PrintThread(object printer)
        {
            //int printid = -1;
            while (true)
            {
                Thread.Sleep(100);
                var print = PublicTool.DicPrintTheadDto[printer.ToString()];
                if (print.PTaskList.Count > 0)
                {
                    var task = print.PTaskList.Where(x => x.Status == "0" || x.Status == "1").OrderBy(x => x.CreateTime).FirstOrDefault();
                    if (task != null)
                    {
                        //if (task.Status != "1")
                        //{
                        //    printid = task.Id;
                        //    new Thread(new ParameterizedThreadStart((o) =>
                        //    {
                        //StartPrintTask(task, printer.ToString());
                        //})).Start();
                        //}

                        if (!PublicTool.IsAllPause)
                        {
                            StartPrintTask(task, printer.ToString());
                        }
                    }

                }
            }
        }
        static void StartPrintTask(TaskInfoEntity task, string printerName)
        {

            string templateType = "0";
            var r_dto = new ReturnDto();
            r_dto.Status = 1; r_dto.MsgId = task.MsgId; r_dto.IsSuccess = true; r_dto.MsgType = task.Type;
            try
            {
                int printcopies = string.IsNullOrEmpty(task.Printcopies) == true ? 1 : int.Parse(task.Printcopies);

                //var param = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(task.Data);
                var param = JsonConvert.DeserializeObject<List<object>>(task.Data);
                var printer = PrinterTool.GetAllPrinter().Where(x => x.PrinterName == printerName).FirstOrDefault();
                if (printer == null)
                {
                    //打印机不存在
                    string ex = string.Format("打印机[{0}]不存在！", printerName);
                    PrintEx(task, printerName, ex, r_dto);
                    return;
                }
                try
                {
                    if (PublicTool.GetTemplatesType.ToLower() == "localfile")//通过本地路径获取打印模板  LocalFile
                    {
                        if (task.Type.ToLower() == "print_bill")//单据打印
                        {
                            templateType = "1";
                        }
                        else  //标签打印 print 或 print_label
                        {
                            templateType = "0";
                        }
                    }
                    else
                    {
                        string ret = "";
                        var url = $"/print/v1/open/template/{task.TemplateInfo}";
                        var ok = PublicTool.HttpGetData($"{ PublicTool.ServerDbIp}{url}", Encoding.UTF8, out ret);
                        if (ok)
                        {
                            var result = JObject.Parse(ret);
                            if (result["code"] != null && result["code"].ToString() != "0")
                            {
                                ok = false;
                                ret = "template:接口异常" + result["message"].ToString();
                            }
                        }
                        if (ok)
                        {
                            var result = JObject.Parse(ret);
                            var isJson =bool.Parse( result["data"]["parameterSourceOut"]["isJson"].ToString());
                            if (isJson)
                            {
                                templateType = "1";
                            }
                        }
                        else
                        {
                            PrintEx(task, printerName, ret, r_dto);
                            return;
                        }


                        //using (var db = MySqlHelper.GetInstance())
                        //{
                        //    var templates = db.Queryable<Fr_TemplatesEntity>()
                        //        .Where(x => x._id == task.TemplateInfo)
                        //        .ToList();
                        //    if (templates.Count() <= 0)
                        //    {
                        //        //模板不存在
                        //        string ex = string.Format("打印模板[{0}]不存在！", task.TemplateInfo);
                        //        PrintEx(task, printerName, ex, r_dto);
                        //        return;
                        //    }
                        //    templateType = templates[0].Type;
                        //};
                    }
                }
                catch (Exception ex)
                {
                    PrintEx(task, printerName, ex.ToString(), r_dto);
                    return;
                }

                var TemplatesSource = "";
                if (string.IsNullOrEmpty(PublicTool.GetTemplatesType) || PublicTool.GetTemplatesType.ToLower() == "sharedfile") //服务器共享文件夹获取打印模板
                {
                    string connServerEx = "";
                    TemplatesSource = GetServerFileTool.GetTemplatePath(PublicTool.ServerTIpPath, PublicTool.ServerTPath, task.TemplateInfo, PublicTool.ServerUser, PublicTool.ServerPW, out connServerEx);
                    if (TemplatesSource == null)
                    {
                        var ex = string.Format("服务器[{0}]连接失败，无法获取模板[{1}]！异常：{2}", PublicTool.ServerTIpPath, task.TemplateInfo, connServerEx);
                        PrintEx(task, printerName, ex, r_dto);
                        return;
                    }
                }
                else if (PublicTool.GetTemplatesType.ToLower() == "api") //通过fastreport服务获取打印模板
                {
                   
                    string ret = "";
                    var url = $"/print/v1/common/frx/{task.TemplateInfo}";
                    var ok = PublicTool.HttpGetData($"{ PublicTool.ServerDbIp}{url}", Encoding.UTF8, out ret);
                    if (ok)
                    {
                        var result = JObject.Parse(ret);
                        if (result["code"] != null && result["code"].ToString() != "0")
                        {
                            ok = false;
                            ret = "common/frx/:接口异常" + result["message"].ToString();
                        }
                    }
                    if (ok)
                    {
                        var result = JObject.Parse(ret);
                        TemplatesSource = result["data"].ToString();
                    }
                    else
                    {
                        PrintEx(task, printerName, ret, r_dto);
                        return;
                    }
                }
                else //通过本地路径获取打印模板  LocalFile
                {
                    TemplatesSource = PublicTool.TemplatesUrl + task.TemplateInfo + ".frx";
                    if (!Directory.Exists(PublicTool.TemplatesUrl) || !File.Exists(TemplatesSource))
                    {
                        var ex = string.Format("模板文件不存在，无法获取模板[{0}]！", TemplatesSource);
                        PrintEx(task, printerName, ex, r_dto);
                        return;
                    }
                }

                if (printer.Status == 3 && printer.PrintJobs == 0)//打印机空闲
                {
                    UpdateTaskStatus(task, "1", "");//开始打印
                    PublicTool.UpdatePrintTheadTaskStatus(printerName, task.Id, "1");

                    Report report = new Report();
                    if (string.IsNullOrEmpty(PublicTool.GetTemplatesType) || PublicTool.GetTemplatesType.ToLower() == "sharedfile" || PublicTool.GetTemplatesType.ToLower() == "localfile")
                    {
                        report.Load(TemplatesSource);
                    }
                    else if (PublicTool.GetTemplatesType.ToLower() == "api")
                    {
                        report.LoadFromString(TemplatesSource);
                    }

                    for (int i = 0; i < param.Count; i++)
                    {
                        if (PublicTool.IsAllPause)
                        {
                            i--;
                            continue;
                        }

                        int PrintCheckNum = int.Parse(PublicTool.PrintCheckNum);
                        var printJobs = PrinterTool.GetAllPrintJobs(printerName);//检测打印机是否存在待打印队列
                        if (PrintCheckNum > 0 && i % PrintCheckNum == 0 && printJobs > 1)//检测数量，是否检测，队列数,
                        {
                            i--;
                            continue;
                        }
                        //foreach (var o in param[i])
                        //{
                        //    FastReport.Data.Parameter frparam = report.Parameters.FindByName(o.Key);
                        //    if (frparam != null)
                        //    {
                        //        report.SetParameterValue(o.Key, o.Value);
                        //    }
                        //}
                        if (templateType == "0")//标签打印
                        {
                            var tmpParam = JsonConvert.DeserializeObject<Dictionary<string, string>>(JsonConvert.SerializeObject(param[i]));
                            for (int n = 0; n < report.AllObjects.Count; n++)
                            {
                                //var basename = report.AllObjects[n].BaseName;
                                var type = report.AllObjects[n].GetType();
                                string expressions = report.AllObjects[n].GetExpressions().FirstOrDefault();

                                expressions = expressions == null ? "" : expressions.TrimEnd(']').TrimStart('[');
                                var isExist = tmpParam.ContainsKey(expressions);
                                if (isExist)
                                {
                                    var value = tmpParam[expressions];
                                    report.SetParameterValue(expressions, value);

                                    //if (basename.ToLower() == "barcode")
                                    //{
                                    //    CodeInfoHandle.SaveCode(task.Source, task.MsgId, value, "0");
                                    //    FastReport.Barcode.BarcodeObject barcodeObject = report.AllObjects[n] as FastReport.Barcode.BarcodeObject;

                                    //    var codeType = barcodeObject.SymbologyName;
                                    //}

                                    if (type.Name == "BarcodeObject")
                                    {
                                        FastReport.Barcode.BarcodeObject barcodeObject = report.AllObjects[n] as FastReport.Barcode.BarcodeObject;

                                        var codeType = barcodeObject.SymbologyName;

                                        CodeInfoHandle.SaveCode(task.Source, task.MsgId, value, codeType, "0");
                                    }
                                }
                            }
                        }
                        else if (templateType == "1")//单据打印
                        {
                            var tmpJsonData = JsonConvert.SerializeObject(param[i]);

                            //根据json创建连接字符串
                            var jdscsb = new FastReport.Data.JsonConnection.JsonDataSourceConnectionStringBuilder();
                            jdscsb.JsonSchema = tmpJsonData;
                            jdscsb.Json = tmpJsonData;

                            var dataObj = (JsonTableDataSource)report.GetDataSource("jsonData");
                            var dataConn = dataObj.Connection;
                            dataConn.ConnectionString = jdscsb.ConnectionString;


                            Dictionary<string, FastReport.Barcode.BarcodeObject> codeObj = new Dictionary<string, FastReport.Barcode.BarcodeObject>();

                            for (int n = 0; n < report.AllObjects.Count; n++)
                            {
                                var type = report.AllObjects[n].GetType();

                                if (type.Name == "BarcodeObject")
                                {
                                    FastReport.Barcode.BarcodeObject barcodeObject = report.AllObjects[n] as FastReport.Barcode.BarcodeObject;

                                    var codeType = barcodeObject.SymbologyName;

                                    if (!string.IsNullOrEmpty(barcodeObject.Text) && !codeObj.ContainsKey(barcodeObject.Text))
                                    {
                                        codeObj.Add(barcodeObject.Text, barcodeObject);
                                    }

                                    if (!string.IsNullOrEmpty(barcodeObject.Expression) && !codeObj.ContainsKey(barcodeObject.Expression))
                                    {
                                        codeObj.Add(barcodeObject.Expression, barcodeObject);
                                    }

                                }
                            }
                            try
                            {
                                SaveCode(task, JObject.Parse(tmpJsonData), codeObj);
                            }
                            catch (Exception ex)
                            {
                                PrintEx(task, printerName, ex.ToString(), r_dto);
                            }
                        }

                        report.PrintSettings.Printer = printerName;
                        report.PrintSettings.ShowDialog = false;
                        (new FastReport.EnvironmentSettings()).ReportSettings.ShowProgress = false;
                        //report.PrintSettings.Copies = 2;
                        //report.Print();

                        for (int c = 0; c < printcopies; c++)
                        {
                            //if (PublicTool.IsAllPause)
                            //{
                            //    c--;
                            //    continue;
                            //}
                            report.Print();
                            TaskLogHandle.SaveLog(task.MsgId, "打印：共：" + param.Count.ToString() + "个标签，每个打印" + printcopies.ToString() + "份，现打印" + (i + 1).ToString() + "-" + (c + 1).ToString(), JsonConvert.SerializeObject(param[i]), "true", "print");
                        }

                        r_dto.Message = "打印第" + (i + 1).ToString() + "个标签";
                        r_dto.Data = param[i];
                        WsServe.SendMessage(task.Source, JsonConvert.SerializeObject(r_dto, Formatting.None, PublicTool.serializerSettings));

                        //TaskLogHandle.SaveLog(task.MsgId, "打印：第" + (i + 1).ToString() + "个标签，共：" + param.Count.ToString(), JsonConvert.SerializeObject(param[i]));
                    }

                    r_dto.Message = "";
                    r_dto.Data = null;
                    r_dto.Status = 2;
                    WsServe.SendMessage(task.Source, JsonConvert.SerializeObject(r_dto, Formatting.None, PublicTool.serializerSettings));

                    UpdateTaskStatus(task, "2", "");
                    PublicTool.RemovePrintTheadTask(printerName, task.Id);
                }
            }
            catch (Exception ex)
            {
                PrintEx(task, printerName, ex.ToString(), r_dto);
            }
        }

        /// <summary>
        /// 保存单据中的条码信息
        /// </summary>
        /// <param name="task">打印任务</param>
        /// <param name="jObject">业务json对象</param>
        /// <param name="codeObj">包含的条码对象</param>
        /// <param name="fkey">默认jsonData. 数据源名称</param>
        public static void SaveCode(TaskInfoEntity task, JObject jObject, Dictionary<string, FastReport.Barcode.BarcodeObject> codeObj, string fkey = "jsonData.")
        {
            if (codeObj.Count <= 0)
            {
                return;
            }
            foreach (var tmpObj in jObject)
            {
                if (tmpObj.Value.GetType().Name == "JArray")
                {
                    var array = tmpObj.Value.ToArray();
                    foreach (var a in array)
                    {
                        SaveCode(task, JObject.Parse(JsonConvert.SerializeObject(a)), codeObj, fkey + tmpObj.Key.ToString() + ".");
                    }
                }
                if (tmpObj.GetType().Name == "JObject")
                {
                    SaveCode(task, JObject.Parse(JsonConvert.SerializeObject(tmpObj.Value)), codeObj, fkey + tmpObj.Key.ToString() + ".");
                }
                else
                {
                    string key = "[" + fkey + tmpObj.Key + "]";
                    key = key.Replace(".", ".item.");
                    if (codeObj.ContainsKey(key))
                    {
                        CodeInfoHandle.SaveCode(task.Source, task.MsgId, tmpObj.Value.ToString(), codeObj[key].SymbologyName, "0");
                    }
                }
            }
        }

        static void UpdateTaskStatus(TaskInfoEntity task, string status, string ex)
        {
            string old_status = task.Status;
            using (var db = SQLiteHelper.GetInstance())
            {
                task.Status = status;
                task.ExInfo = ex;
                task.EndTime = task.UpdateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");

                if (status == "1")
                {
                    task.StartTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                    db.Updateable(task).UpdateColumns(it => new { it.Status, it.ExInfo, it.StartTime }).ExecuteCommand();
                }
                else if (status == "2" || status == "3")
                {
                    var tmpTask = db.Queryable<TaskInfoEntity>().Where(x => x.Id == task.Id).First();
                    tmpTask.Status = status;
                    tmpTask.StartTime = task.StartTime == null ? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") : tmpTask.StartTime;
                    tmpTask.EndTime = tmpTask.UpdateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                    TaskInfoHandle.SaveTaskHistory(tmpTask.Id.ToString(), tmpTask);

                    db.Deleteable<TaskInfoEntity>().Where(x => x.Id == task.Id).ExecuteCommand();
                }
                else
                {
                    db.Updateable(task).UpdateColumns(it => new { it.Status, it.ExInfo, it.EndTime }).ExecuteCommand();
                }
            };
            TaskLogHandle.SaveLog(task.MsgId, "打印：修改任务状态", string.Format("状态：{0}->{1}", old_status, status));
        }
        static void PrintEx(TaskInfoEntity task, string printerName, string ex, ReturnDto r_dto)
        {
            //模板不存在
            UpdateTaskStatus(task, "5", ex);
            r_dto.Status = 3;
            r_dto.IsSuccess = false;
            r_dto.Message = ex;
            WsServe.SendMessage(task.Source, JsonConvert.SerializeObject(r_dto, Formatting.None, PublicTool.serializerSettings));

            PublicTool.UpdatePrintTheadTaskStatus(printerName, task.Id, "5");

            TaskLogHandle.SaveLog(task.MsgId, "打印：异常", ex, "false");
        }
    }
}
